home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagg_m.zip / MEMORY.SWG / 0016_Extend HEAP to UMB.pas < prev    next >
Pascal/Delphi Source File  |  1993-05-29  |  10KB  |  281 lines

  1. {$A-,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S+,V-,X-}
  2.  
  3. Unit UMB_Heap;
  4.  
  5. {----------------------------------------------------------------------------}
  6.  
  7. interface
  8.  
  9.   Procedure Extend_Heap;        { Use Upper Memory Blocks (UMB) to extend    }
  10.                                 { the Turbo Pascal 6.0 heap.  This procedure }
  11.                                 { should be called as soon as possible in    }
  12.                                 { your code.                                 }
  13.   var
  14.     UMB_Heap_Debug : Boolean;   { If true, releases UMBs immediately to make }
  15.                                 { sure they're available for the next run    }
  16.                                 { without rebooting.  Used when debugging in }
  17.                                 { the IDE.  If not used then, the UMBs may   }
  18.                                 { not get freed between executions.          }
  19.  
  20. {----------------------------------------------------------------------------}
  21.  
  22. implementation
  23.  
  24. const
  25.   Max_Blocks = 4;              { It's not likely more than 4 UMBs are needed }
  26.  
  27. type
  28.   PFreeRec = ^TFreeRec;      {  From pg. 216 of the TP6 programmer's guide.  }
  29.   TFreeRec = record          {  It's used for traversing the free blocks of  }
  30.     Next : PFreeRec;         {  the heap.                                    }
  31.     Size : Pointer;
  32.   end;
  33.  
  34. var
  35.   XMS_Driver : Pointer;      {  Pointer to the XMS driver.  }
  36.   Num_Blocks : Word;
  37.   Block_Address,
  38.   Block_Size : Array[1..Max_Blocks+1] of Pointer;
  39.   SaveExitProc : Pointer;
  40.  
  41. {----------------------------------------------------------------------------}
  42.  
  43. {  Swap to pointers.  Needed when sorting the UMB addresses.  }
  44.  
  45. Procedure Pointer_Swap(var A,B : Pointer);
  46.   var
  47.     Temp : Pointer;
  48.   Begin
  49.     Temp := A;
  50.     A := B;
  51.     B := Temp;
  52.   End;
  53.  
  54. {----------------------------------------------------------------------------}
  55.  
  56. Function XMS_Driver_Present : Boolean;  { XMS software present? }
  57.   var
  58.     Result : Boolean;
  59.   Begin
  60.     Result := False;      { Assume no XMS driver }
  61.     asm
  62.       @Begin:
  63.         mov ax,4300h
  64.         int 2Fh
  65.         cmp al,80h
  66.         jne @Fail
  67.         mov ax,4310h
  68.         int 2Fh
  69.         mov word ptr XMS_Driver+2,es       { Get the XMS driver entry point }
  70.         mov word ptr XMS_Driver,bx
  71.         mov Result,1
  72.         jmp @End
  73.       @Fail:
  74.         mov Result,0
  75.       @End:
  76.     end;
  77.     XMS_Driver_Present := Result;
  78.   End;
  79.  
  80. {----------------------------------------------------------------------------}
  81.  
  82. Procedure Allocate_UMB_Heap;         { Add the four largest UMBs to the heap }
  83.   var
  84.     i,j : Word;
  85.     UMB_Strategy,
  86.     DOS_Strategy,
  87.     Segment,Size : Word;
  88.     Get_Direct : Boolean;   { Get UMB direct from XMS if TRUE, else from DOS }
  89.   Begin
  90.     Num_Blocks := 0;
  91.  
  92.     for i := 1 to Max_Blocks do
  93.       begin
  94.         Block_Address[i] := nil;
  95.         Block_Size[i] := nil;
  96.       end;
  97.  
  98.     asm
  99.       mov ax,5800h
  100.       int 21h                     { Get and save the DOS allocation strategy }
  101.       mov [DOS_Strategy],ax
  102.       mov ax,5802h
  103.       int 21h                     { Get and save the UMB allocation strategy }
  104.       mov [UMB_Strategy],ax
  105.       mov ax,5801h
  106.       mov bx,0000h
  107.       int 21h                      { Set the DOS allocation strategy so that }
  108.       mov ax,5803h                 { it uses only high memory                }
  109.  
  110.                                    { DON'T TRUST THIS FUNCTION.  DOS WILL GO }
  111.                                    { AHEAD AND TRY TO ALLOCATE LOWER MEMORY  }
  112.                                    { EVEN AFTER YOU TELL IT NOT TO!          }
  113.       mov bx,0001h
  114.       int 21h                      { Set the UMB allocation strategy so that }
  115.     end;                           { UMBs are added to the DOS mem chain     }
  116.  
  117.     Get_Direct := True;            { Try to get UMBs directly from the XMS   }
  118.                                    { if possible.                            }
  119.     for i := 1 to Max_Blocks do
  120.       begin
  121.         Segment := 0;
  122.         Size := 0;
  123.  
  124.         if Get_Direct then         { Get a UMB direct from the XMS driver.   }
  125.           begin
  126.             asm
  127.               @Begin:
  128.                 mov ax,01000h         
  129.                 mov dx,0FFFFh         { Ask for the impossible to ...        }
  130.                 push ds               { Get the size of the next largest UMB }
  131.                 mov cx,ds
  132.                 mov es,cx
  133.                 call es:[XMS_Driver]
  134.                 cmp dx,100h           { Don't bother with anything < 1K      }
  135.                 jl @End
  136.                 mov ax,01000h
  137.                 call es:[XMS_Driver]  { Get the next largest UMB }
  138.                 cmp ax,1
  139.                 jne @End
  140.                 cmp bx,0A000h         { It better be above 640K }
  141.                 jl @End               { We can't trust DOS 5.00 }
  142.                 mov [Segment],bx
  143.                 mov [Size],dx
  144.               @End:
  145.                 pop ds
  146.             end;
  147.             if ((i = 1) and (Size = 0)) then  { if we couldn't get the UMB  }
  148.               Get_Direct := False;            { from the XMS driver, don't  }
  149.           end;                                { try again the next time.    }
  150.  
  151.         if (not Get_Direct) then   { Get a UMB via DOS }
  152.           begin
  153.             asm
  154.               @Begin:
  155.                 mov ax,4800h
  156.                 mov bx,0FFFFh         { Ask for the impossible to ...        }
  157.                 int 21h               { Get the size of the next largest UMB }
  158.                 cmp bx,100h           { Don't bother with anything < 1K      }
  159.                 jl @End
  160.                 mov ax,4800h
  161.                 int 21h               { Get the next largest UMB }
  162.                 jc @End
  163.                 cmp ax,0A000h         { It better be above 640K }
  164.                 jl @End               { We can't trust DOS 5.00 }
  165.                 mov [Segment],ax
  166.                 mov [Size],bx
  167.               @End:
  168.             end;
  169.           end;
  170.  
  171.         if (Segment > 0) then                      { Did it work? }
  172.           begin
  173.             Block_Address[i] := Ptr(Segment,0);
  174.             Inc(Num_Blocks);
  175.           end;
  176.         Block_Size[i] := Ptr(Size,0);
  177.       end;
  178.     if (Num_Blocks > 0) then               { Sort the UMB addrs in ASC order }
  179.       begin
  180.         for i := 1 to Num_Blocks-1 do
  181.           for j := i+1 to Num_Blocks do
  182.             if (Seg(Block_Address[i]^) > Seg(Block_Address[j]^)) then
  183.               begin
  184.                 Pointer_Swap(Block_Address[i],Block_Address[j]);
  185.                 Pointer_Swap(Block_Size[i],Block_Size[j]);
  186.               end;
  187.       end;
  188.     asm
  189.       mov ax,5803h
  190.       mov bx,[UMB_Strategy]
  191.       int 21h                          { Restore the UMB allocation strategy }
  192.       mov ax,5801h
  193.       mov bx,[DOS_Strategy]
  194.       int 21h                          { Restore the DOS allocation strategy }
  195.     end;
  196.   End;
  197.  
  198. {----------------------------------------------------------------------------}
  199.  
  200. Procedure Release_UMB; far;                 { Exit procedure to release UMBs }
  201.   var
  202.     i : Word;
  203.     Segment : Word;
  204.   Begin
  205.     ExitProc := SaveExitProc;
  206.     if (Num_Blocks > 0) then
  207.       begin
  208.         asm
  209.           mov ax,5803h
  210.           mov bx,0000h
  211.           int 21h                       { Set the UMB status to release UMBs }
  212.         end;
  213.         for i := 1 to Num_Blocks do
  214.           begin
  215.             Segment := Seg(Block_Address[i]^);
  216.             if (Segment > 0) then
  217.               asm
  218.                 mov ax,$4901
  219.                 mov bx,[Segment]
  220.                 mov es,bx
  221.                 int 21h                                    { Release the UMB }
  222.               end;
  223.           end;
  224.       end;
  225.   End;
  226.  
  227. {----------------------------------------------------------------------------}
  228.  
  229. Procedure Extend_Heap;
  230.   var
  231.     i : Word;
  232.     Temp : PFreeRec;
  233.   Begin
  234.     if XMS_Driver_Present then
  235.       begin
  236.         Allocate_UMB_Heap;
  237.         if UMB_Heap_Debug then
  238.           Release_UMB;
  239.         if (Num_Blocks > 0) then
  240.           begin                             { Attach UMBs to the FreeList    }
  241.             for i := 1 to Num_Blocks do
  242.               PFreeRec(Block_Address[i])^.Size := Block_Size[i];
  243.             for i := 1 to Num_Blocks do
  244.               PFreeRec(Block_Address[i])^.Next := Block_Address[i+1];
  245.  
  246.             PFreeRec(Block_Address[Num_Blocks])^.Next := nil;
  247.  
  248.             if (FreeList = HeapPtr) then
  249.               with PFreeRec(FreeList)^ do
  250.                 begin
  251.                   Next := Block_Address[1];
  252.                   Size := Ptr(Seg(HeapEnd^)-Seg(HeapPtr^),0);
  253.                 end
  254.             else
  255.               with PFreeRec(HeapPtr)^ do
  256.                 begin
  257.                   Next := Block_Address[1];
  258.                   Size := Ptr(Seg(HeapEnd^)-Seg(HeapPtr^),0);
  259.                 end;
  260.  
  261.             { HEAPPTR MUST BE IN THE LAST FREE BLOCK SO
  262.               THAT TP6 DOESN'T TRY TO USE ANY MEMORY BETWEEN
  263.               640K AND HEAPPTR }
  264.  
  265.             HeapPtr := Block_Address[Num_Blocks];
  266.             HeapEnd := Ptr(Seg(Block_Address[Num_Blocks]^)+Seg(Block_Size[Num_Blocks]^),0);
  267.           end;
  268.       end;
  269.   End;
  270.  
  271. {----------------------------------------------------------------------------}
  272.  
  273. BEGIN
  274.   UMB_Heap_Debug := False;
  275.   Num_Blocks := 0;
  276.   SaveExitProc := ExitProc;
  277.   ExitProc := @Release_UMB;
  278. END.
  279.  
  280. {----------------------------------------------------------------------------}
  281.